#pragma once

#include "DiagnosticBag.hpp"

#include "BoundExpression.hpp"
#include "BoundGlobalScope.hpp"
#include "BoundScope.hpp"
#include "BoundStatement.hpp"

#include "Syntax/Expression/AssignmentExpression.hpp"
#include "Syntax/Expression/BinaryExpression.hpp"
#include "Syntax/Expression/Expression.hpp"
#include "Syntax/Expression/LiteralExpression.hpp"
#include "Syntax/Expression/NameExpression.hpp"
#include "Syntax/Expression/UnaryExpression.hpp"
#include <Syntax/Expression/ParenthesizedExpression.hpp>

#include "Syntax/Statement/BlockStatement.hpp"
#include "Syntax/Statement/ExpressionStatement.hpp"
#include "Syntax/Statement/ForStatement.hpp"
#include "Syntax/Statement/IfStatement.hpp"
#include "Syntax/Statement/Statement.hpp"
#include "Syntax/Statement/VariableDeclaration.hpp"
#include "Syntax/Statement/WhileStatement.hpp"

#include "Syntax/CompilationUnit.hpp"

#include "Symbol/TypeSymbol.hpp"

class Binder
{
public:
    Binder(SharedBoundScope parent);

public:
    // 静态方法;
    static SharedBoundGlobalScope BindGlobalScope(SharedBoundGlobalScope previous, SharedCompilationUnit syntax);
    static SharedBoundScope       CreateParentScope(SharedBoundGlobalScope previous);

public:
    SharedBoundStatement  BindStatement(SharedStatement syntax);
    SharedBoundExpression BindExpression(SharedExpression syntax);
    SharedBoundExpression BindExpression(SharedExpression syntax, SharedTypeSymbol targetType);

private:
    // exoression;
    SharedBoundExpression BindNameExpression(NameExpressionSyntax *syntax);
    SharedBoundExpression BindUnaryExpression(UnaryExpressionSyntax *syntax);
    SharedBoundExpression BindBinaryExpression(BinaryExpressionSyntax *syntax);
    SharedBoundExpression BindLiteralExpression(LiteralExpressionSyntax *syntax);
    SharedBoundExpression BindAssignmentExpression(AssignmentExpressionSyntax *syntax);
    SharedBoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntax *syntax);

private:
    // statement;
    SharedBoundStatement BindIfStatement(IfStatementSyntax *syntax);
    SharedBoundStatement BindForStatement(ForStatementSyntax *syntax);
    SharedBoundStatement BindWhileStatement(WhileStatementSyntax *syntax);
    SharedBoundStatement BindBlockStatement(BlockStatementSyntax *syntax);
    SharedBoundStatement BindExpressionStatement(ExpressionStatementSyntax *syntax);
    SharedBoundStatement BindVeriableDeclaration(VariableDeclarationSyntax *syntax);

private:
    // variable;
    SharedVariableSymbol BindVariable(SharedToken identifier, bool isReadOnly, SharedTypeSymbol type);

private:
    // 变量;
    SharedBoundScope Scope;
    // 诊断;
    SharedDiagnosticBag diagnostics;
};